// D9 - D16  LED流水灯   也是控制 8x8 LED 逐行扫描用

#include <reg51.h>           //此文件中定义了单片机的一些特殊功能寄存器
#include <intrins.h>

typedef unsigned int u16;     //对数据类型进行声明定义
typedef unsigned char u8;

sbit SRCLK = P3 ^ 6;
sbit RCLK = P3 ^ 5;   // 这个变量名 reg52.h 头文件有使用，所以使用 reg51.h
sbit SER = P3 ^ 4;

// D9 - D16  LED流水灯
u8 ledduan[] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};     // 逐列点亮不改
/*******************************************************************************
* 函 数 名         : delay
* 函数功能         : 延时函数，i=1时，大约延时10us
*******************************************************************************/
void delay(u16 i)
{
    while (i--);
}

/*******************************************************************************
* 函数名         : Hc595SendByte(u8 dat)
* 函数功能         : 向74HC595发送一个字节的数据
    74595的控制端说明：
    SCK(11脚)：上升沿时数据寄存器的数据移位。QA-->QB-->QC-->...-->QH；下降沿移位寄存器数据不变。
    RCK(12脚)：上升沿时移位寄存器的数据进入数据存储寄存器，下降沿时存储寄存器数据不变。
               通常我将RCK置为低点平，当移位结束后，在RCK端产生一个正脉冲，更新显示数据。
*******************************************************************************/
void Hc595SendByte(u8 dat)
{
    u8 a;
    SRCLK = 0;
    RCLK = 0;
    for (a = 0; a < 8; a++) {
        SER = dat >> 7;  // 获取最高位  0xA3 :  1010 0011  等于 1
        dat <<= 1;      //  数据移位，移除最高位1补0  0100 0110

        SRCLK = 1;    // 上升沿时数据寄存器的数据移位
        _nop_();
        _nop_();      // 延时
        SRCLK = 0;    // 下降沿移位寄存器数据不变
    }

    RCLK = 1;   // 上升沿时移位寄存器的数据进入数据存储寄存器
    _nop_();
    _nop_();    // 延时
    RCLK = 0;   // 下降沿时存储寄存器数据不变
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能       : 主函数
* 输    入       : 无
* 输    出         : 无
*******************************************************************************/
void main()
{
    u8 i;
    while (1) {
        P0 = 0x7f; // 8x8 LED
        for (i = 0; i < 8; i++) {
            Hc595SendByte(ledduan[i]);  //发送段选数据
            delay(55000);        //延时
        }

        for (i = 0; i < 8; i++) {
            Hc595SendByte(~ledduan[i]);  //发送段选数据
            delay(55000);        //延时
        }
    }
}
